package com.dy.yunying.biz.service.gametask.impl;


import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dy.yunying.api.constant.Constant;
import com.dy.yunying.api.entity.ParentGameDO;
import com.dy.yunying.api.entity.gametask.GameTaskConfig;
import com.dy.yunying.api.entity.gametask.ImportGameTaskConfig;
import com.dy.yunying.api.req.gametask.GameTaskConfigReq;
import com.dy.yunying.api.req.gametask.GameTaskSelectReq;
import com.dy.yunying.api.req.gametask.ImportGameTaskReq;
import com.dy.yunying.api.resp.gametask.GameTaskConfigRes;
import com.dy.yunying.biz.dao.ads.gametask.GameTaskConfigMapper;
import com.dy.yunying.biz.service.gametask.GameTaskConfigService;
import com.dy.yunying.biz.service.manage.ParentGameService;
import com.dy.yunying.biz.utils.StringUtil;
import com.pig4cloud.pig.common.core.util.CommonUtils;
import com.pig4cloud.pig.common.core.util.R;
import com.pig4cloud.pig.common.security.util.SecurityUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * 游戏任务配置service
 * @author sunyq
 */
@Slf4j
@Service("gameTaskConfigService")
@RequiredArgsConstructor
public class GameTaskConfigServiceImpl extends ServiceImpl<GameTaskConfigMapper, GameTaskConfig> implements GameTaskConfigService {

	private final String FILE_SUFFIX_XLSX = "xlsx";

	private final String FILE_SUFFIX_XLS = "xls";

	private final ParentGameService parentGameService;

	@Override
	@Transactional(rollbackFor = Exception.class)
	public R importGameTaskConfig(ImportGameTaskReq importGameTaskReq) throws IOException {
		//
		if (importGameTaskReq.getParentGameId() == null) {
			return R.failed("主游戏不能为空");
		}
		final MultipartFile gameTaskExcelFile = importGameTaskReq.getGameTaskExcelFile();
		if (gameTaskExcelFile == null || gameTaskExcelFile.isEmpty()) {
			return R.failed("上传文件不能为空");
		}
		// 获取名称
		String filename = gameTaskExcelFile.getOriginalFilename();
		// 获取后缀名
		String suffix = filename.substring(filename.lastIndexOf(".") + 1);

		if (!FILE_SUFFIX_XLSX.equals(suffix) && !FILE_SUFFIX_XLS.equals(suffix)) {
			return R.failed("文件仅支持.xls、.xlsx格式");
		}
		AtomicInteger paramErrorCount = new AtomicInteger();
		AtomicInteger totalCount = new AtomicInteger();
		AtomicInteger notMatchCount = new AtomicInteger();
		// 查询所导入的aapId
		final String appId = baseMapper.getAppIdByParentGameId(importGameTaskReq.getParentGameId());
		EasyExcel.read(gameTaskExcelFile.getInputStream(), ImportGameTaskConfig.class, new CustomAnalysisEventListener(paramErrorCount, totalCount, notMatchCount, importGameTaskReq, appId)).sheet().doRead();
		StringBuilder message = new StringBuilder();
		message.append("导入游戏任务配置成功 ").append(totalCount.get() - paramErrorCount.get() - notMatchCount.get())
				.append("  条,").append(" 其中必填参数为空/字段超长 ")
				.append(paramErrorCount.get()).append(" 条, 父游戏id和appId不匹配 ").append(notMatchCount).append(" 条！");
		return R.ok(0, message.toString());
	}

	@Override
	public R getGameTaskListByParentGameIds(List<Long> parentGameIds) {
		List<GameTaskConfig> gameTaskListByParentGameIds = baseMapper.getGameTaskListByParentGameIds(parentGameIds);
		if (CollectionUtils.isEmpty(gameTaskListByParentGameIds)) {
			return R.ok(gameTaskListByParentGameIds);
		}
		List<GameTaskConfigRes> collect = gameTaskListByParentGameIds.stream().map(gameTaskConfig -> {
			GameTaskConfigRes gameTaskConfigRes = new GameTaskConfigRes();
			BeanUtils.copyProperties(gameTaskConfig, gameTaskConfigRes);
			return gameTaskConfigRes;
		}).collect(Collectors.toList());
		return R.ok(collect);
	}

	@Override
	public R getPage(GameTaskSelectReq gameTaskSelectReq) {
		QueryWrapper<GameTaskConfig> query = getQueryWrapper(gameTaskSelectReq);
		Page<GameTaskConfig> page = new Page<>();
		page.setCurrent(gameTaskSelectReq.getCurrent());
		page.setSize(gameTaskSelectReq.getSize());
		Page<GameTaskConfig> gameTaskConfigPage = baseMapper.selectPage(page, query);

		List<GameTaskConfig> records = gameTaskConfigPage.getRecords();
		Page<GameTaskConfigRes> resultPage = new Page<GameTaskConfigRes>(page.getCurrent(), page.getSize());
		if (!CollectionUtils.isEmpty(records)) {
			resultPage.setTotal(gameTaskConfigPage.getTotal());
			resultPage.setCountId(gameTaskConfigPage.getCountId());
			resultPage.setPages(gameTaskConfigPage.getPages());
			List<GameTaskConfigRes> resultList = new ArrayList<GameTaskConfigRes>();
			List<Long> parentGameIds = records.stream().map(gameTaskConfig -> gameTaskConfig.getParentGameId()).collect(Collectors.toList());
			//获取主游戏名称
			List<ParentGameDO> parentGameDos = parentGameService.listByIds(parentGameIds);
			Map<Long, List<ParentGameDO>> collect = parentGameDos.stream().collect(Collectors.groupingBy(ParentGameDO::getId));
			for (GameTaskConfig record : records) {
				GameTaskConfigRes gameTaskConfigRes = new GameTaskConfigRes();
				BeanUtils.copyProperties(record, gameTaskConfigRes);
				List<ParentGameDO> gameDos = collect.get(record.getParentGameId());
				gameTaskConfigRes.setParentGameName(gameDos.get(0).getGname());
				resultList.add(gameTaskConfigRes);
			}
			resultPage.setRecords(resultList);
		}
		return R.ok(resultPage);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public R createEdit(GameTaskConfigReq gameTaskConfigReq) {
		GameTaskConfig gameTaskConfig = new GameTaskConfig();
		BeanUtils.copyProperties(gameTaskConfigReq, gameTaskConfig);
		if (gameTaskConfig.getId() == null) {
			//查询是否存在 parentGameId、appId、taskId是否存在
			List<GameTaskConfig> gameTaskConfigs = baseMapper.selectList(Wrappers.<GameTaskConfig>lambdaQuery()
					.eq(GameTaskConfig::getParentGameId, gameTaskConfig.getParentGameId())
					.eq(GameTaskConfig::getAppId, gameTaskConfig.getAppId())
					.eq(GameTaskConfig::getTaskId, gameTaskConfig.getTaskId()));
			if (!CollectionUtils.isEmpty(gameTaskConfigs)) {
				return R.failed("已存在相同的parentGameId、appId、taskId数据，请确认配置数据！");
			}
			gameTaskConfig.setDeleted(Constant.DEL_NO);
			gameTaskConfig.setCreateId(SecurityUtils.getUser().getId().longValue());
			gameTaskConfig.setCreateTime(new Date());
			baseMapper.saveWithReplace(gameTaskConfig);
		} else {
			gameTaskConfig.setUpdateId(SecurityUtils.getUser().getId().longValue());
			gameTaskConfig.setUpdateTime(new Date());
			this.updateById(gameTaskConfig);
		}
		return R.ok(0, "创建/编辑游戏任务配置成功");
	}

	@Override
	public R getAppIdByParentGameId(Long parentGameId) {
		String appIdByParentGameId = baseMapper.getAppIdByParentGameId(parentGameId);
		if (appIdByParentGameId == null) {
			return R.ok("", "获取app_id成功");
		}
		return R.ok(appIdByParentGameId, "获取app_id成功");
	}

	private QueryWrapper<GameTaskConfig> getQueryWrapper(GameTaskSelectReq gameTaskSelectReq) {
		QueryWrapper<GameTaskConfig> query = new QueryWrapper<GameTaskConfig>();
		final Long parentGameId = gameTaskSelectReq.getParentGameId();
		final String taskDescription = gameTaskSelectReq.getTaskDescription();
		if (parentGameId != null) {
			query.eq("parent_game_id", parentGameId);
		}
		if (!StringUtils.isEmpty(taskDescription)) {
			query.like("task_description", taskDescription);
		}
		query.eq("deleted", Constant.DEL_NO);
		query.orderByDesc("id");
		return query;

	}

	public class CustomAnalysisEventListener extends AnalysisEventListener<ImportGameTaskConfig> {

		private AtomicInteger paramErrorCount;
		private AtomicInteger totalCount;
		private AtomicInteger notMatchCount;
		private ImportGameTaskReq importGameTaskReq;
		private String appId;

		public CustomAnalysisEventListener(AtomicInteger paramErrorCount, AtomicInteger totalCount, AtomicInteger notMatchCount, ImportGameTaskReq importGameTaskReq, String appId) {
			this.paramErrorCount = paramErrorCount;
			this.importGameTaskReq = importGameTaskReq;
			this.totalCount = totalCount;
			this.notMatchCount = notMatchCount;
			this.appId = appId;
		}

		final int batchCount = 100;

		List<GameTaskConfig> gameTaskConfigs = new ArrayList<>();

		@Override
		public void onException(Exception exception, AnalysisContext context) throws Exception {
			//异常处理
			super.onException(exception, context);
		}

		@Override
		public void invoke(ImportGameTaskConfig importGameTaskConfig, AnalysisContext context) {
			totalCount.incrementAndGet();
			//处理
			if (null == importGameTaskConfig) {
				return;
			}
			if (StringUtil.isBlank(importGameTaskConfig.getAppId())) {
				paramErrorCount.incrementAndGet();
				return;
			}
			if (StringUtil.isBlank(importGameTaskConfig.getTaskId()) || importGameTaskConfig.getTaskId().length() > 18 || !CommonUtils.isPositiveNumber(importGameTaskConfig.getTaskId())) {
				paramErrorCount.incrementAndGet();
				return;
			}
			if (StringUtil.isBlank(importGameTaskConfig.getTaskDescription()) || importGameTaskConfig.getTaskDescription().length() > 50) {
				paramErrorCount.incrementAndGet();
				return;
			}
			if (!importGameTaskConfig.getAppId().equals(appId)) {
				notMatchCount.incrementAndGet();
				return;
			}
			GameTaskConfig gameTaskConfig = new GameTaskConfig();
			BeanUtils.copyProperties(importGameTaskConfig, gameTaskConfig);
			gameTaskConfig.setParentGameId(importGameTaskReq.getParentGameId());
			gameTaskConfig.setCreateId(SecurityUtils.getUser().getId().longValue());
			gameTaskConfig.setUpdateId(SecurityUtils.getUser().getId().longValue());
			gameTaskConfig.setCreateTime(new Date());
			gameTaskConfig.setUpdateTime(new Date());
			gameTaskConfig.setDeleted(Constant.DEL_NO);
			gameTaskConfigs.add(gameTaskConfig);
			if (gameTaskConfigs.size() >= batchCount) {
				baseMapper.batchSaveWithReplace(gameTaskConfigs);
				gameTaskConfigs.clear();
			}
		}

		@Override
		public void doAfterAllAnalysed(AnalysisContext context) {
			if (gameTaskConfigs.size() > 0) {
				baseMapper.batchSaveWithReplace(gameTaskConfigs);
				gameTaskConfigs.clear();
			}
		}
	}
}
